import * as Cesium from 'cesium'

/**
 * Cesium鼠标事件处理类
 * 提供完整的鼠标事件监听和处理功能
 */
class MouseEventHandler {
  constructor(viewer) {
    this.viewer = viewer
    this.scene = viewer.scene
    this.canvas = viewer.canvas
    this.handler = new Cesium.ScreenSpaceEventHandler(this.canvas)

    // 鼠标状态跟踪
    this.mouseState = {
      leftPressed: false,
      middlePressed: false,
      rightPressed: false,
      lastPosition: null
    }

    // 事件回调存储
    this.callbacks = {
      leftDown: [],
      leftUp: [],
      leftDrag: [], // 左键按下后移动
      rightDown: [],
      rightUp: [],
      middleDown: [],
      middleUp: [],
      middleDrag: [], // 中键按下后移动
      wheel: [], // 中键滚动
      mouseMove: []
    }

    this.initEvents()
  }

  /**
   * 初始化所有鼠标事件
   */
  initEvents () {
    // 左键按下事件
    this.handler.setInputAction((event) => {
      this.mouseState.leftPressed = true
      this.mouseState.lastPosition = event.position

      this.triggerCallbacks('leftDown', {
        position: event.position,
        pickedObject: this.scene.pick(event.position),
        cartesian: this.getCartesian(event.position),
        cartographic: this.getCartographic(event.position)
      })
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN)

    // 左键弹起事件
    this.handler.setInputAction((event) => {
      this.mouseState.leftPressed = false
      this.mouseState.lastPosition = null

      this.triggerCallbacks('leftUp', {
        position: event.position,
        pickedObject: this.scene.pick(event.position),
        cartesian: this.getCartesian(event.position),
        cartographic: this.getCartographic(event.position)
      })
    }, Cesium.ScreenSpaceEventType.LEFT_UP)

    // 右键按下事件
    this.handler.setInputAction((event) => {
      this.mouseState.rightPressed = true

      this.triggerCallbacks('rightDown', {
        position: event.position,
        pickedObject: this.scene.pick(event.position),
        cartesian: this.getCartesian(event.position),
        cartographic: this.getCartographic(event.position)
      })
    }, Cesium.ScreenSpaceEventType.RIGHT_DOWN)

    // 右键弹起事件
    this.handler.setInputAction((event) => {
      this.mouseState.rightPressed = false

      this.triggerCallbacks('rightUp', {
        position: event.position,
        pickedObject: this.scene.pick(event.position),
        cartesian: this.getCartesian(event.position),
        cartographic: this.getCartographic(event.position)
      })
    }, Cesium.ScreenSpaceEventType.RIGHT_UP)

    // 中键按下事件
    this.handler.setInputAction((event) => {
      this.mouseState.middlePressed = true
      this.mouseState.lastPosition = event.position

      this.triggerCallbacks('middleDown', {
        position: event.position,
        pickedObject: this.scene.pick(event.position),
        cartesian: this.getCartesian(event.position),
        cartographic: this.getCartographic(event.position)
      })
    }, Cesium.ScreenSpaceEventType.MIDDLE_DOWN)

    // 中键弹起事件
    this.handler.setInputAction((event) => {
      this.mouseState.middlePressed = false
      this.mouseState.lastPosition = null

      this.triggerCallbacks('middleUp', {
        position: event.position,
        pickedObject: this.scene.pick(event.position),
        cartesian: this.getCartesian(event.position),
        cartographic: this.getCartographic(event.position)
      })
    }, Cesium.ScreenSpaceEventType.MIDDLE_UP)

    // 鼠标滚轮事件（中键滚动）
    this.handler.setInputAction((event) => {
      // 获取当前鼠标位置，使用画布中心作为默认位置
      const canvasCenter = new Cesium.Cartesian2(
        this.canvas.clientWidth / 2,
        this.canvas.clientHeight / 2
      )

      this.triggerCallbacks('wheel', {
        delta: event,
        position: canvasCenter,
        pickedObject: this.scene.pick(canvasCenter),
        cartesian: this.getCartesian(canvasCenter),
        cartographic: this.getCartographic(canvasCenter)
      })
    }, Cesium.ScreenSpaceEventType.WHEEL)

    // 鼠标移动事件
    this.handler.setInputAction((event) => {
      const eventData = {
        startPosition: event.startPosition,
        endPosition: event.endPosition,
        pickedObject: this.scene.pick(event.endPosition),
        cartesian: this.getCartesian(event.endPosition),
        cartographic: this.getCartographic(event.endPosition)
      }

      // 触发通用鼠标移动事件
      this.triggerCallbacks('mouseMove', eventData)

      // 检查是否为拖拽事件
      if (this.mouseState.leftPressed) {
        // 左键拖拽事件
        this.triggerCallbacks('leftDrag', {
          ...eventData,
          dragType: 'left',
          startPosition: this.mouseState.lastPosition || event.startPosition
        })
      }

      if (this.mouseState.middlePressed) {
        // 中键拖拽事件
        this.triggerCallbacks('middleDrag', {
          ...eventData,
          dragType: 'middle',
          startPosition: this.mouseState.lastPosition || event.startPosition
        })
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
  }

  /**
   * 获取鼠标当前位置
   */
  getMousePosition () {
    const rect = this.canvas.getBoundingClientRect()
    // 注意：这个方法需要在事件回调中使用，因为需要event对象
    // 如果需要在其他地方使用，可以传入event参数
    return new Cesium.Cartesian2(0, 0) // 默认返回原点
  }

  /**
   * 获取鼠标当前位置（带event参数）
   */
  getMousePositionFromEvent (event) {
    const rect = this.canvas.getBoundingClientRect()
    return new Cesium.Cartesian2(
      event.clientX - rect.left,
      event.clientY - rect.top
    )
  }

  /**
   * 获取屏幕坐标对应的笛卡尔坐标
   */
  getCartesian (position) {
    if (!position) return null

    try {
      // 尝试从地形获取坐标
      const cartesian = this.viewer.camera.pickEllipsoid(position, this.scene.globe.ellipsoid)
      if (cartesian) {
        return cartesian
      }

      // 如果地形拾取失败，尝试从3D Tiles获取
      const pickedObject = this.scene.pick(position)
      if (Cesium.defined(pickedObject)) {
        const cartesian3 = this.scene.pickPosition(position)
        if (Cesium.defined(cartesian3)) {
          return cartesian3
        }
      }

      return null
    } catch (error) {
      console.warn('获取笛卡尔坐标失败:', error)
      return null
    }
  }

  /**
   * 获取屏幕坐标对应的地理坐标
   */
  getCartographic (position) {
    const cartesian = this.getCartesian(position)
    if (!cartesian) return null

    try {
      const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
      return {
        longitude: Cesium.Math.toDegrees(cartographic.longitude),
        latitude: Cesium.Math.toDegrees(cartographic.latitude),
        height: cartographic.height
      }
    } catch (error) {
      console.warn('获取地理坐标失败:', error)
      return null
    }
  }

  /**
   * 触发回调函数
   */
  triggerCallbacks (eventType, eventData) {
    this.callbacks[eventType].forEach(callback => {
      try {
        callback(eventData)
      } catch (error) {
        console.error(`鼠标事件回调执行失败 (${eventType}):`, error)
      }
    })
  }

  /**
   * 添加事件监听器
   * @param {string} eventType - 事件类型
   * @param {function} callback - 回调函数
   */
  addEventListener (eventType, callback) {
    if (this.callbacks[eventType] && typeof callback === 'function') {
      this.callbacks[eventType].push(callback)
    } else {
      console.warn(`不支持的事件类型: ${eventType}`)
    }
  }

  /**
   * 移除事件监听器
   * @param {string} eventType - 事件类型
   * @param {function} callback - 回调函数
   */
  removeEventListener (eventType, callback) {
    if (this.callbacks[eventType]) {
      const index = this.callbacks[eventType].indexOf(callback)
      if (index > -1) {
        this.callbacks[eventType].splice(index, 1)
      }
    }
  }

  /**
   * 移除所有事件监听器
   * @param {string} eventType - 事件类型（可选）
   */
  removeAllEventListeners (eventType) {
    if (eventType) {
      if (this.callbacks[eventType]) {
        this.callbacks[eventType] = []
      }
    } else {
      Object.keys(this.callbacks).forEach(key => {
        this.callbacks[key] = []
      })
    }
  }

  /**
   * 启用/禁用特定事件类型
   * @param {string} eventType - 事件类型
   * @param {boolean} enabled - 是否启用
   */
  setEventEnabled (eventType, enabled) {
    const eventTypeMap = {
      leftDown: Cesium.ScreenSpaceEventType.LEFT_DOWN,
      leftUp: Cesium.ScreenSpaceEventType.LEFT_UP,
      leftDrag: Cesium.ScreenSpaceEventType.MOUSE_MOVE, // 左键拖拽依赖鼠标移动
      rightDown: Cesium.ScreenSpaceEventType.RIGHT_DOWN,
      rightUp: Cesium.ScreenSpaceEventType.RIGHT_UP,
      middleDown: Cesium.ScreenSpaceEventType.MIDDLE_DOWN,
      middleUp: Cesium.ScreenSpaceEventType.MIDDLE_UP,
      middleDrag: Cesium.ScreenSpaceEventType.MOUSE_MOVE, // 中键拖拽依赖鼠标移动
      wheel: Cesium.ScreenSpaceEventType.WHEEL,
      mouseMove: Cesium.ScreenSpaceEventType.MOUSE_MOVE
    }

    const cesiumEventType = eventTypeMap[eventType]
    if (cesiumEventType) {
      if (enabled) {
        // 重新初始化特定事件
        this.initSpecificEvent(eventType, cesiumEventType)
      } else {
        // 移除特定事件
        this.handler.removeInputAction(cesiumEventType)
      }
    } else {
      console.warn(`不支持的事件类型: ${eventType}`)
    }
  }

  /**
   * 初始化特定事件
   */
  initSpecificEvent (eventType, cesiumEventType) {
    // 这里可以根据需要重新设置特定事件
    // 为了简化，这里只是一个占位符
    console.log(`重新初始化事件: ${eventType}`)
  }

  /**
   * 获取当前鼠标状态
   * @returns {Object} 鼠标状态对象
   */
  getMouseState () {
    return {
      leftPressed: this.mouseState.leftPressed,
      middlePressed: this.mouseState.middlePressed,
      rightPressed: this.mouseState.rightPressed,
      lastPosition: this.mouseState.lastPosition
    }
  }

  /**
   * 检查特定鼠标按键是否被按下
   * @param {string} button - 按键类型 ('left', 'middle', 'right')
   * @returns {boolean} 是否被按下
   */
  isButtonPressed (button) {
    switch (button) {
      case 'left':
        return this.mouseState.leftPressed
      case 'middle':
        return this.mouseState.middlePressed
      case 'right':
        return this.mouseState.rightPressed
      default:
        return false
    }
  }

  /**
   * 获取支持的事件类型列表
   * @returns {Array} 支持的事件类型
   */
  getSupportedEventTypes () {
    return Object.keys(this.callbacks)
  }

  /**
   * 销毁事件处理器
   */
  destroy () {
    if (this.handler) {
      this.handler.destroy()
      this.handler = null
    }
    this.callbacks = null
    this.mouseState = null
    this.viewer = null
    this.scene = null
    this.canvas = null
  }
}

// 使用示例和工具函数
export const createMouseEventHandler = (viewer) => {
  return new MouseEventHandler(viewer)
}

// 常用的事件处理工具函数
export const MouseEventUtils = {
  /**
   * 判断是否点击在实体上
   */
  isEntityPicked (pickedObject) {
    return Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id)
  },

  /**
   * 判断是否点击在3D Tiles上
   */
  is3DTilesPicked (pickedObject) {
    return Cesium.defined(pickedObject) && pickedObject instanceof Cesium.Cesium3DTileFeature
  },

  /**
   * 判断是否点击在地形上
   */
  isTerrainPicked (pickedObject) {
    return !Cesium.defined(pickedObject)
  },

  /**
   * 格式化地理坐标显示
   */
  formatCoordinates (cartographic) {
    if (!cartographic) return '无效坐标'

    return `经度: ${cartographic.longitude.toFixed(6)}°, 纬度: ${cartographic.latitude.toFixed(6)}°, 高度: ${cartographic.height.toFixed(2)}m`
  },

  /**
   * 计算两个屏幕坐标之间的距离
   */
  calculateScreenDistance (pos1, pos2) {
    if (!pos1 || !pos2) return 0

    const dx = pos2.x - pos1.x
    const dy = pos2.y - pos1.y
    return Math.sqrt(dx * dx + dy * dy)
  },

  /**
   * 计算拖拽的方向
   */
  calculateDragDirection (startPos, endPos) {
    if (!startPos || !endPos) return null

    const dx = endPos.x - startPos.x
    const dy = endPos.y - startPos.y

    if (Math.abs(dx) > Math.abs(dy)) {
      return dx > 0 ? 'right' : 'left'
    } else {
      return dy > 0 ? 'down' : 'up'
    }
  },

  /**
   * 判断是否为有效的拖拽（移动距离超过阈值）
   */
  isValidDrag (startPos, endPos, threshold = 5) {
    return this.calculateScreenDistance(startPos, endPos) > threshold
  },

  /**
   * 获取事件类型的中文描述
   */
  getEventTypeDescription (eventType) {
    const descriptions = {
      leftDown: '鼠标左键按下',
      leftUp: '鼠标左键弹起',
      leftDrag: '鼠标左键拖拽',
      rightDown: '鼠标右键按下',
      rightUp: '鼠标右键弹起',
      middleDown: '鼠标中键按下',
      middleUp: '鼠标中键弹起',
      middleDrag: '鼠标中键拖拽',
      wheel: '鼠标滚轮',
      mouseMove: '鼠标移动'
    }
    return descriptions[eventType] || '未知事件'
  }
}

export default MouseEventHandler

